#pragma once
#include <iostream>
#include <unordered_map>
#include <string>
#include <sstream>
#include <algorithm>
#include <fcntl.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <sys/stat.h>
#include <sys/sendfile.h>
#include <sys/wait.h>
#include "LogMessage.hpp"
#include "Util.hpp"

using std::cout;
using std::endl;
using std::string;

const string WEBROOT = "./webroot";
const string INDEX_PAGE = "index.html";
const string HTTP_VERSION = "HTTP/1.0";
const string CRLF = "\r\n";
const int CGI_OK = 0;
const int CGI_BADREQUEST = 1;

static std::unordered_map<int, string> StateDescMap =
    {{200, "OK"}, {404, "Not Found"}, {400, "Bad Request"}, {500, "Internal Server Error"}};

static std::unordered_map<string, string> FileTypeMap =
    {{".html", "text/html"}, {".css", "text/css"}, {".jpg", "application/x-jpg"}, {".js", "application/x-javascript"}, {".xml", "text/xml"}, {".png", "application/x-png"}, {".jpeg", "image/jpeg"}, {".mp3", "audio/mp3"}};

class Request
{
public:
    bool Deserialize(string &buffer);

    void DebugPrint();

public:
    string _method;
    string _uri;
    string _url;
    string _queryStr;
    string _version;
    std::unordered_map<string, string> _header;
    string _content;
    bool _cgi = false;
};

class Response
{
public:
    string Serialize();

    void DebugPrint();

    ~Response()
    {
        if (_fd != -1)
        {
            close(_fd);
        }
    }

public:
    string _version;
    int _stateCode = 200; // 状态码
    string _stateDesc;
    std::unordered_map<string, string> _header;
    int _fd = -1; // 要返回的静态内容直接从文件中读取
    string _fileType;
    int _fileSize = 0;
    string _content; // content保存CGI程序的处理结果
};

class EndPoint
{
public:
    EndPoint(int sockfd)
        : _sockfd(sockfd)
    {
    }

    // 获取一个完整报文并作反序列化
    bool GetReq();
    
    int AnalyseReq();

    void BuildResp();

    void SendResp();

    void DebugPrint();

private:
    Request _req;
    Response _resp;
    string _path; // 本地路径
    int _sockfd;

    // 检查请求的资源，并打开
    int CheckResource();

    int CGI();
};